package com.umeox.watch.moto.contact.ui

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioManager
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.os.Bundle
import android.os.CountDownTimer
import android.os.PowerManager
import android.os.RemoteException
import android.text.TextUtils
import android.view.KeyEvent
import android.view.View
import android.view.WindowManager
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import coil.load
import coil.transform.CircleCropTransformation
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.request.RequestOptions
import com.umeox.moto.common.executor.ThreadExecutor
import com.umeox.moto.common.log.Logger
import com.umeox.moto.watch.themes.util.UToast
import com.umeox.moto.watch.themes.app.ThemeAppCompatActivity
import com.umeox.moto.watch.themes.widget.CircleWaveView
import com.umeox.watch.moto.agora.AgoraService
import com.umeox.watch.moto.agora.InternalConstants
import com.umeox.watch.moto.apiclient.model.VoipTokenDTO
import com.umeox.watch.moto.contact.R
import com.umeox.watch.moto.contact.base.GlideApp
import com.umeox.watch.moto.contact.model.ContactDetail
import com.umeox.watch.moto.contact.utils.Utils
import com.umeox.watch.moto.dataservice.DataProvider
import com.umeox.watch.moto.dataservice.proxy.VideocallProxy
import java.util.*

class SinglePTTActivity : ThemeAppCompatActivity(), AgoraService.RtcEventChangeListener,
    AgoraService.RemoteAudioStateChangedLister {

    private var isConnected: Boolean = false
    private var isOutCall: Boolean = false
    private var friendId: String? = null
    private var contact: ContactDetail? = null

    private lateinit var peerAvatarIv: ImageView
    private lateinit var backBtn: TextView
    private lateinit var agoraService: AgoraService

    private var channel: String? = null
    private lateinit var peer: String

    private lateinit var videoCallBinder: VideocallProxy

    private var voipTokenDTO: VoipTokenDTO? = null
    private lateinit var mSpreadViewMe: CircleWaveView
    private lateinit var mSpreadViewPeer: CircleWaveView
    private lateinit var mAudioManager: AudioManager

    private lateinit var connectLl: View
    private lateinit var tvConnectingTip: TextView

    private var player: MediaPlayer? = null

    private var mPeerHangupReceiverIsRegistered = false

    private var isHangupByMyself = false

    private var volumeSettingDialog: VolumeSettingDialog? = null


    private val mDownTimer: CountDownTimer = object :
        CountDownTimer(60 * 1000L, 1000) {
        override fun onTick(millisUntilFinished: Long) {
            val secs = 60 - millisUntilFinished / 1000
            if (connectLl.visibility == View.GONE) {
                connectLl.visibility = View.VISIBLE
            }
            tvConnectingTip.text = String.format(
                Locale.CHINA, getString(R.string.str_connecting_format), secs % 3600 / 60,
                secs % 60
            )
        }

        override fun onFinish() {
            tvConnectingTip.text = getString(R.string.str_no_response)
            tvConnectingTip.postDelayed({
                runOnUiThread {
                    connectLl.visibility = View.GONE
                    agoraService.endCall()
                }
                logger("通知服务器取消邀请>>>" + notifyCancelPTT())
            }, 2000)
        }
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val pm = getSystemService(POWER_SERVICE) as PowerManager
        val wakeLock = pm.newWakeLock(
            PowerManager.ACQUIRE_CAUSES_WAKEUP or PowerManager.SCREEN_DIM_WAKE_LOCK,
            "My:Tag"
        )
        wakeLock.acquire(5000)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        val intent = intent
        val uri = intent.data
        if (uri != null) {
            isOutCall = InternalConstants.CALL_TYPE_PTT_OUT == uri.path
            Logger.e("uri= $uri")
            if (!isOutCall) {//来电
                channel = uri.getQueryParameter(InternalConstants.CALL_QUERY_PARA_CHANNEL)
            }
            friendId = uri.getQueryParameter(InternalConstants.CALL_QUERY_PARA_FOLLOWER_ID)
        }
        if (TextUtils.isEmpty(friendId)) {
            Logger.i("被叫方ID为空，退出应用")
            finish()
            return
        }

        contact = Utils.getContactByFriendId(friendId)
        if (contact == null) {
            Logger.i("没有找到联系人，退出应用")
            finish()
            return
        }
        setContentView(R.layout.activity_single_ptt)

        mAudioManager = getSystemService(AUDIO_SERVICE) as AudioManager
        mAudioManager.requestAudioFocus(
            null,
            AudioManager.STREAM_VOICE_CALL,
            AudioManager.AUDIOFOCUS_GAIN
        )

        agoraService = AgoraService.getInstance(this)
        agoraService.setCallType(AgoraService.CALL_TYPE_PTT)
        agoraService.setFriendId(friendId!!)
        agoraService.setEventHandler(this)
        agoraService.setRemoteAudioStateChangedListener(this)
        peer = friendId!!
        if (isOutCall) {
            channel = friendId + "_" + System.currentTimeMillis()
        }

        videoCallBinder = VideocallProxy.fetchBinder() as VideocallProxy

        initView()
        agoraService.muteLocalAudioStream(true)

        connectLl.postDelayed(mAcceptInviteRunnable, 1000)

        registerPeerHangupReceiver()
    }


    private val mAcceptInviteRunnable = Runnable {
        this@SinglePTTActivity.runOnUiThread {
            if (!isOutCall) {
                if (!isOutCall) {
                    try {
                        agoraService.acceptInvite(channel!!)
                        isConnected = true
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }

                }
            }
        }
    }


    private fun registerPeerHangupReceiver() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(com.umeox.watch.moto.dataservice.constants.Constants.ACTION_CANCEL_AGORA_CALL)
        registerReceiver(mPeerHangupReceiver, intentFilter)
        mPeerHangupReceiverIsRegistered = true
    }

    private val mPeerHangupReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action ?: return
            agoraService.endCall()
            finish()
        }
    }

    @Suppress("MISSING_DEPENDENCY_CLASS")
    override fun onPostCreate(savedInstanceState: Bundle?) {
        super.onPostCreate(savedInstanceState)
        if (isOutCall) {
            startRingtone()
            //目前登录需要Token，所以要先拿Token
            try {
                voipTokenDTO =
                    videoCallBinder.getVoipToken(DataProvider.getHolderId(), friendId, channel)
                if (voipTokenDTO != null) {
                    logger("voipTokenDTO:$voipTokenDTO")
                    peer = voipTokenDTO!!.rtmToMemberId
                    ThreadExecutor.getInstance().io().execute {
                        agoraService.login(
                            voipTokenDTO!!.rtmFromMemberId,
                            voipTokenDTO!!.rtmToken
                        )
                    }
                } else {
                    Toast.makeText(this, R.string.call_device_offline, Toast.LENGTH_SHORT)
                        .show()
                }
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }

    }


    /**
     * 开始响铃
     */
    private fun startRingtone() {
        try {
            stopRingtone()
            player = MediaPlayer()
            val ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
            player?.setDataSource(this, ringtone)
            player?.setAudioStreamType(AudioManager.STREAM_RING)
            player?.isLooping = true
            player?.prepare()
            player?.start()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 停止响铃
     */
    private fun stopRingtone() {
        if (player != null && player!!.isPlaying) {
            player!!.stop()
            player!!.reset()
            player!!.release()
            player = null
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        mAudioManager.abandonAudioFocus(null)
        mDownTimer.cancel()
        stopRingtone()
        isHangupByMyself = false
        if (mPeerHangupReceiverIsRegistered && mPeerHangupReceiver != null) {
            unregisterReceiver(mPeerHangupReceiver)
            mPeerHangupReceiverIsRegistered = false
        }
        connectLl.removeCallbacks(mAcceptInviteRunnable)
    }

    private fun initView() {
        backBtn = findViewById(R.id.back_btn)
        tvConnectingTip = findViewById(R.id.tv_connect_tip)
        connectLl = findViewById(R.id.connect_ll)
        backBtn.text = contact?.contactName
        backBtn.setOnClickListener {
            if (isOutCall) {
                isOutCall = false
                mDownTimer.cancel()
                connectLl.visibility = View.GONE
                if (!isConnected) {
                    ThreadExecutor.getInstance().io().execute {
                        logger("通知服务器取消邀请>>>" + notifyCancelPTT())
                    }
                }
            }
            isHangupByMyself = true
            agoraService.endCall()
            //finish()
        }
        findViewById<ImageView>(R.id.iv_end).setOnClickListener {
            if (isOutCall) {
                isOutCall = false
                mDownTimer.cancel()
                connectLl.visibility = View.GONE
                if (!isConnected) {
                    ThreadExecutor.getInstance().io().execute {
                        logger("通知服务器取消邀请>>>" + notifyCancelPTT())
                    }
                }
            }
            isHangupByMyself = true
            agoraService.endCall()
            finish()
        }

        peerAvatarIv = findViewById(R.id.peer_avatar_iv)
        if (contact?.contactPhotoUrl.isNullOrEmpty()) {
            peerAvatarIv.load(R.drawable.default_avatar) {
                transformations(CircleCropTransformation())
            }
        } else {
//            peerAvatarIv.load(contact?.contactPhotoUrl) {
//                transformations(CircleCropTransformation())
//            }

            GlideApp.with(mContext)
                .load(contact?.contactPhotoUrl)
                .apply(RequestOptions.bitmapTransform(CircleCrop()))
                .into(peerAvatarIv)
        }
        findViewById<ImageView>(R.id.iv_volume).setOnClickListener {
            if (volumeSettingDialog == null) {
                volumeSettingDialog = VolumeSettingDialog(this, isConnected)
            }
            volumeSettingDialog?.setIsAnswer(isConnected)
            volumeSettingDialog?.show()
        }

        mSpreadViewMe = findViewById(R.id.sv_view_me)
        mSpreadViewPeer = findViewById(R.id.sv_view_peer)

        if (isOutCall) {
            mDownTimer.start()
        }
    }

    private fun inviteJoinPTT(friendId: String, channel: String): Int {
        try {
            return videoCallBinder.inviteJoinPTT(friendId, channel)
        } catch (e: Exception) {
            Logger.e("invite join voice call failed：$e")
            e.printStackTrace()

        }
        return -1
    }

    /**
     * 通过aidl调用api通知app取消当前通话
     */
    private fun notifyCancelPTT(): Boolean {
        try {
            return videoCallBinder.notifyCancelPTT(friendId, channel)
        } catch (e: Exception) {
            Logger.e("notify cancel voice call failed：$e")
            e.printStackTrace()
        }
        return false
    }

    override fun onLoggedIn() {
        if (isOutCall) {
            try {
                logger("登录信令成功，开始邀请APP端")
                val result: Int = inviteJoinPTT(friendId!!, channel!!)
                logger("邀请结果>>>$result")
                when (result) {
                    0 -> {
                        agoraService.inviteCall(
                            channel!!,
                            peer,
                            voipTokenDTO!!.channelToken,
                            voipTokenDTO!!.rtcMemberId
                        )
                        return
                    }
                    40405 -> {
                        runOnUiThread {
                            Toast.makeText(this, R.string.call_in_class_mode, Toast.LENGTH_SHORT)
                                .show()
                        }
                        logger("对方正在上课模式，即将退出")
                    }
                    40406 -> {
                        runOnUiThread {
                            Toast.makeText(this, R.string.call_device_offline, Toast.LENGTH_SHORT)
                                .show()
                        }
                        logger("对方不在线，即将退出")
                    }
                    else -> {
                        runOnUiThread {
                            Toast.makeText(
                                this,
                                R.string.call_send_request_fail,
                                Toast.LENGTH_SHORT
                            ).show()
                        }
                        logger("发送邀请失败，即将退出")
                    }
                }
                agoraService.endCall()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

    }

    override fun onInviteRefused(response: String?) {
        if (isOutCall) {
            mDownTimer.cancel()
            if (response != null && response.contains("1000")) {
                runOnUiThread {
                    UToast.showCustomToast(
                        this@SinglePTTActivity,
                        resources.getString(R.string.call_busy),
                        Toast.LENGTH_LONG
                    )
                }
            } else {
                runOnUiThread {
                    UToast.showCustomToast(
                        this@SinglePTTActivity,
                        getString(R.string.str_peer_refused),
                        Toast.LENGTH_LONG
                    )
                }
            }
            logger("对方拒绝接听，即将退出。")
            stopRingtone()
            agoraService.endCall()
        }
    }

    override fun onUserJoined(uid: Int) {
        stopRingtone()
        agoraService.muteLocalAudioStream(true)
        if (isOutCall) {
            mDownTimer.cancel()
            isConnected = true
            runOnUiThread {
                connectLl.visibility = View.GONE
                UToast.showCustomToast(
                    this@SinglePTTActivity,
                    getString(R.string.str_connected),
                    Toast.LENGTH_LONG
                )
            }
        }
    }

    override fun onFirstRemoteFrame(uid: Int) {

    }

    override fun onTiming(secs: Int) {
    }

    override fun onInviteEnd() {
        logger("结束呼叫成功，退出应用")
        agoraService.endCall()
        isOutCall = false
    }

    override fun onCallEnd(totalDuration: Int) {
        logger("PTT通话结束>>>$totalDuration")
        isOutCall = false
        if (totalDuration > 0 && !isHangupByMyself) {
            runOnUiThread {
                Toast.makeText(
                    mContext,
                    resources.getString(R.string.hung_up_str),
                    Toast.LENGTH_LONG
                ).show()
            }
        }

        if (!isFinishing) {
            finish()
        }
    }

    override fun onWarning(warn: Int) {
    }

    override fun switch2VideoMode(mode: Int) {
    }

    override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
//        if (txQuality == Constants.QUALITY_POOR || txQuality == Constants.QUALITY_BAD || txQuality == Constants.QUALITY_VBAD || txQuality == Constants.QUALITY_DOWN || rxQuality == Constants.QUALITY_POOR || rxQuality == Constants.QUALITY_BAD || rxQuality == Constants.QUALITY_VBAD || rxQuality == Constants.QUALITY_DOWN) {
//            runOnUiThread {
//                try {
//                    UToast.show(
//                        "Poor connection",
//                        Toast.LENGTH_SHORT
//                    )
//                }catch (e:Exception){
//                    e.printStackTrace()
//                }
//
//            }
//        }
    }

    override fun onPeerNoResponse() {

    }

    override fun onInviteTimeout() {
    }

    private fun logger(text: String) {
        Logger.w(text)
    }

    override fun onBackPressed() {
        if (isOutCall) {
            isOutCall = false
            mDownTimer.cancel()
            connectLl.visibility = View.GONE
            if (!isConnected) {
                ThreadExecutor.getInstance().io().execute {
                    logger("通知服务器取消邀请>>>" + notifyCancelPTT())
                }
            }
        }
        isHangupByMyself = true
        agoraService.endCall()
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (isConnected && keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
            //按下推流
            agoraService.muteLocalAudioStream(false)
            //播放动画
            mSpreadViewMe.visibility = View.VISIBLE
            mSpreadViewMe.start()
            return true
        }
        return super.onKeyDown(keyCode, event)
    }

    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
        if (isConnected && keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
            agoraService.muteLocalAudioStream(true)
            mSpreadViewMe.stop()
            mSpreadViewMe.visibility = View.GONE
            return true
        }
        return super.onKeyUp(keyCode, event)
    }

    override fun remoteAudioMuted() {
        Logger.e("远端用户停止发送音频流")
        runOnUiThread {
            mSpreadViewPeer.stop()
            mSpreadViewPeer.visibility = View.GONE
        }
    }

    override fun remoteAudioUnuted() {
        Logger.e("远端用户恢复发送音频流")
        runOnUiThread {
            mSpreadViewPeer.visibility = View.VISIBLE
            mSpreadViewPeer.start()
        }
    }

}